﻿using Furion.CMS.Application;
using Furion.CMS.Application.Dto;
using Furion.CMS.Core;
using Furion.CMS.Domain;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Web.Core.FileUpload
{
    /// <summary>
    /// 腾讯云COS文件上传
    /// </summary>
    [Injection(Named = nameof(StorageMode.TencentCOS))]
    public class TencentCOSFileUpload : IFileUploadProvider, ITransient
    {
        private readonly SiteSettingAppService siteSetting;
        private readonly DateTime UTC_START_TIME = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

        /// <summary>
        /// 站点设置信息
        /// </summary>
        public SiteSetting Site { get => siteSetting.GetTenantSettings(); }

        /// <summary>
        /// 存储库参数
        /// </summary>
        public ObjectStorageParams Storage { get => Site?.ObjectStorageParam; }

        public TencentCOSFileUpload(SiteSettingAppService siteSetting)
        {
            this.siteSetting = siteSetting;
        }

        public string CallbackHandler(ICloudCallbackModel callbackParams)
        {
            if (callbackParams is TencentCOSCallbackModel tencentCOSCallback)
            {
                return $"{Storage.Url}/{tencentCOSCallback.Key}";
            }
            throw Oops.Oh("参数错误");
        }


        /// <summary>
        /// 获取腾讯云COS配置
        /// </summary>
        /// <returns></returns>
        public UploadConfigre GetConfigre()
        {
            // 设置单次上传凭据的有效时间为10分钟
            var expireDateTime = DateTime.Now.AddMinutes(10); // 设置单次上传凭据的有效时间为10分钟
            long durationSecond = 600;  //每次请求签名有效时长，单位为秒
            long keyStartTime = (long)(DateTime.UtcNow - UTC_START_TIME).TotalSeconds;
            var keyTime = $"{keyStartTime};{keyStartTime + durationSecond}";

            var host = Storage.Url;
            var accessKeyID = Storage.KeyId;
            var accessKeySecret = Storage.KeySecret;
            // 计算签名Key
            var signKey = keyTime.ToHMAC(accessKeySecret, true);
            var callbackHost = Site.HostUrl;

#if DEBUG
            // debug模式下,使用mock来接收回调并返回消息体
            callbackHost = "https://www.fastmock.site/mock/b15e2648340c7c065b87828d6e1d893d/furion-cms";
#endif
            var callbackUrl = $"{callbackHost}/api/file-center/cloud-callback/tencent";

            // policy关键参数
            var signAlgorithm = new JObject();
            signAlgorithm.Add("q-sign-algorithm", "sha1");
            var ak = new JObject();
            ak.Add("q-ak", accessKeyID);
            var signTime = new JObject();
            signTime.Add("q-sign-time", keyTime);

            var policyObj = new Dictionary<string, object>() {
                    {"expiration",expireDateTime.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'",CultureInfo.CurrentCulture) },
                    {"conditions",new object[]{
                        signAlgorithm,
                        ak,
                        signTime,
                        new object[] { "starts-with", "$success_action_redirect", callbackUrl },
                    } }
                };

            var policyStr = Newtonsoft.Json.JsonConvert.SerializeObject(policyObj);
            var signature = policyStr.ToSHA1(true).ToHMAC(signKey, true);
            var policy = Convert.ToBase64String(Encoding.Default.GetBytes(policyStr));

            // 组装扩展数据
            var extraData = new Dictionary<string, object>();
            extraData.Add("policy", policy);
            extraData.Add("q-sign-algorithm", "sha1");
            extraData.Add("q-ak", accessKeyID);
            extraData.Add("q-key-time", keyTime);
            extraData.Add("q-signature", signature);
            extraData.Add("success_action_redirect", callbackUrl);

            return new UploadConfigre
            {
                Host = host,
                ExtraData = extraData,
            };
        }
    }
}
